"""
测试执行器模块
负责执行API测试用例，支持单用例执行和数据驱动批量执行
"""

import requests
import time
import re
from typing import Dict, Any, List, Optional
from .assertion_engine import AssertionEngine
from .data_source import DataSource


class TestExecutor:
    """测试执行器"""
    
    def __init__(self, base_url: str = '', timeout: int = 30):
        """
        初始化执行器
        
        Args:
            base_url: API基础URL
            timeout: 请求超时时间（秒）
        """
        self.base_url = base_url.rstrip('/')
        self.timeout = timeout
        self.session = requests.Session()
    
    def execute_case(self, test_case: Dict[str, Any], data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        执行单个测试用例
        
        Args:
            test_case: 测试用例
            data: 测试数据（用于占位符替换）
            
        Returns:
            执行结果
        """
        # 如果提供了测试数据，替换占位符
        if data:
            test_case = self._replace_placeholders(test_case, data)
        
        # 构造请求
        url = self._build_url(test_case.get('url', ''))
        method = test_case.get('method', 'GET').upper()
        parameters = test_case.get('parameters', [])
        body = test_case.get('body')
        
        # 准备请求参数
        headers = {}
        params = {}
        path_params = {}
        
        for param in parameters:
            param_name = param.get('name')
            param_value = param.get('example')
            param_in = param.get('in', 'query')
            
            if param_in == 'header':
                headers[param_name] = param_value
            elif param_in == 'query':
                params[param_name] = param_value
            elif param_in == 'path':
                path_params[param_name] = param_value
        
        # 替换路径参数
        for param_name, param_value in path_params.items():
            url = url.replace(f'{{{param_name}}}', str(param_value))
        
        # 准备请求体
        request_data = None
        request_json = None
        
        if body:
            body_type = body.get('type', 'json')
            body_content = body.get('content')
            
            if body_type == 'json':
                request_json = body_content
                headers['Content-Type'] = 'application/json'
            elif body_type == 'form':
                request_data = body_content
                headers['Content-Type'] = 'application/x-www-form-urlencoded'
        
        # 执行请求
        start_time = time.time()
        
        try:
            response = self.session.request(
                method=method,
                url=url,
                headers=headers,
                params=params,
                data=request_data,
                json=request_json,
                timeout=self.timeout
            )
            
            end_time = time.time()
            response_time = int((end_time - start_time) * 1000)  # 转换为毫秒
            
            # 解析响应体
            try:
                response_body = response.json()
            except:
                response_body = response.text
            
            # 构造响应数据
            response_data = {
                'status_code': response.status_code,
                'body': response_body,
                'headers': dict(response.headers),
                'response_time': response_time
            }
            
            # 执行断言
            assertions = test_case.get('assertions', [])
            assertion_results = AssertionEngine.execute_assertions(assertions, response_data)
            
            # 判断用例是否通过
            result = 'success' if assertion_results['failed'] == 0 else 'failed'
            
            # 构造执行结果
            execution_result = {
                'case_id': test_case.get('case_id'),
                'case_name': test_case.get('case_name'),
                'result': result,
                'response_time': response_time,
                'request_detail': {
                    'url': url,
                    'method': method,
                    'headers': headers,
                    'params': params,
                    'body': request_json or request_data
                },
                'response_detail': response_data,
                'assertion_results': assertion_results,
                'error_msg': None,
                'execute_time': time.strftime('%Y-%m-%d %H:%M:%S')
            }
            
            return execution_result
            
        except requests.Timeout:
            return self._build_error_result(test_case, '请求超时', url, method)
        
        except requests.ConnectionError:
            return self._build_error_result(test_case, '连接失败', url, method)
        
        except Exception as e:
            return self._build_error_result(test_case, f'执行异常: {str(e)}', url, method)
    
    def _build_url(self, path: str) -> str:
        """构造完整URL"""
        if path.startswith('http://') or path.startswith('https://'):
            return path
        
        path = path.lstrip('/')
        return f"{self.base_url}/{path}"
    
    def _replace_placeholders(self, test_case: Dict[str, Any], data: Dict[str, Any]) -> Dict[str, Any]:
        """
        替换测试用例中的占位符
        
        Args:
            test_case: 测试用例
            data: 测试数据
            
        Returns:
            替换后的测试用例
        """
        import json
        import copy
        
        # 深拷贝，避免修改原始用例
        test_case = copy.deepcopy(test_case)
        
        # 将用例转换为JSON字符串
        case_str = json.dumps(test_case, ensure_ascii=False)
        
        # 替换所有占位符 {{key}}
        for key, value in data.items():
            placeholder = f'{{{{{key}}}}}'
            case_str = case_str.replace(placeholder, str(value))
        
        # 转换回字典
        test_case = json.loads(case_str)
        
        return test_case
    
    def _build_error_result(self, test_case: Dict[str, Any], error_msg: str, 
                           url: str, method: str) -> Dict[str, Any]:
        """构造错误结果"""
        return {
            'case_id': test_case.get('case_id'),
            'case_name': test_case.get('case_name'),
            'result': 'failed',
            'response_time': 0,
            'request_detail': {
                'url': url,
                'method': method
            },
            'response_detail': None,
            'assertion_results': {
                'total': 0,
                'passed': 0,
                'failed': 0,
                'details': []
            },
            'error_msg': error_msg,
            'execute_time': time.strftime('%Y-%m-%d %H:%M:%S')
        }


class DataDrivenExecutor:
    """数据驱动执行器"""
    
    def __init__(self, base_url: str = '', timeout: int = 30):
        """
        初始化数据驱动执行器
        
        Args:
            base_url: API基础URL
            timeout: 请求超时时间（秒）
        """
        self.executor = TestExecutor(base_url, timeout)
    
    def execute_with_data_source(self, test_cases: List[Dict[str, Any]], 
                                 data_source: DataSource) -> List[Dict[str, Any]]:
        """
        使用数据源执行测试用例
        
        Args:
            test_cases: 测试用例列表
            data_source: 数据源
            
        Returns:
            执行结果列表
        """
        # 读取测试数据
        test_data_list = data_source.read_data()
        
        results = []
        
        # 遍历测试数据
        for index, test_data in enumerate(test_data_list):
            data_id = f"data_{index + 1}"
            
            # 对每个用例执行测试
            for test_case in test_cases:
                result = self.executor.execute_case(test_case, test_data)
                result['data_id'] = data_id
                result['data_index'] = index + 1
                results.append(result)
        
        return results
    
    def execute_batch(self, test_cases: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        批量执行测试用例（不使用数据源）
        
        Args:
            test_cases: 测试用例列表
            
        Returns:
            执行结果列表
        """
        results = []
        
        for test_case in test_cases:
            result = self.executor.execute_case(test_case)
            results.append(result)
        
        return results
